//PARADIME INTERPRETER
//
//LICENSED FREELY UNDER MIT.
//CREATED FOR FREE USE.

#include "stdafx.h"
#include "tokentypes.h"
#include "Interpreter.h"
#include "variabledomain.h"
#include "variant.h"
#include "Parser.h"

//Consider putting the operator lookup in a MAP to increase performance.

#define OPERATORPREC_COUNT 32 //Increment this by two for every new entry to the op table.
char OperatorsPrec[][2] =	{	{'A'},{(char)1},	//AND
								{'O'},{(char)1},	//OR
								{'='},{(char)2},
								{'D'},{(char)2},
								{'<'},{(char)2},
								{'>'},{(char)2},
								{'L'},{(char)2},	//<=
								{'G'},{(char)2},	//>=
								{'T'},{(char)2},	//<>
								{'&'},{(char)3},
								{'+'},{(char)4},
								{'-'},{(char)4},
								{'*'},{(char)5},
								{'/'},{(char)5},
								{'^'},{(char)6},
								{'!'},{(char)7}		//NOT
							};

//Returns 0 if not found.
int GetPrecedence(char c){
	int iterator = 0;
	for(; iterator<OPERATORPREC_COUNT;iterator+=2){
		if(OperatorsPrec[iterator][0] == c)return (int)OperatorsPrec[iterator+1][0];
	}
	return 0;
}

char Operator(std::string in){

	if(in=="AND")return 'A'; if(in=="OR")return 'O';
	if(in=="+")return '+'; if(in=="-")return '-'; if(in=="/")return '/'; if(in=="*")return '*';
	if(in=="&")return '&';
	if(in=="<")return '<'; if(in==">")return '>'; if(in=="=")return '='; if(in=="<=")return 'L'; if(in==">=")return 'G';
	if(in=="^")
			return '^';
	if(in=="!")
			return '!';
	if(in=="==")
			return 'D';
	if(in=="<>")
			return 'T';
	if(in=="NOT")
			return '!';
	return (char)0;
}

bool op_left_assoc(const char c)
{
    switch(c)    {
        // left to right
		case '*': case '/': case '%': case '+': case '-': case '&': case '^':
            return true;
        // right to left
		case '=': case '!': case 'A': case 'O':
            return false;
    }
    return false;
}

//Wrapper function to create token variable; not used anymore.
token CreateToken(int type, std::string data){
	token* t = new token;
	t->data = data;
	t->type = type;
	return *t;
}


std::vector<token> ShuntExpression(std::vector<token>* exp, Interpreter* QueryOwner){

	VariableDomain* domain = static_cast<VariableDomain*>(QueryOwner->Domain);
	std::vector<token> RPNExpression;
	std::stack<token> RPNstack;
	std::stack<token> OPstack;
	token LastToken;
	token result;
	int iterator = 0;
	int dims[VAR_SUBSCRIPT_MAX];

	for(; iterator<(*exp).size();iterator++){
		token Currenttoken = (*exp)[iterator];
		Variant* var;

		switch(Currenttoken.type){
			//Push all the literals to the stack.
			case NUMHEX_TOK: case INT32_TOK: case INT64_TOK: case DOUBLE_TOK: case STRINGLITERAL_TOK:
				RPNstack.push(Currenttoken);
				break;

			case FUNC_UNKNOWN_TOK:
				//Will gather params, increment FOR loop, execute, get result and everything!
				if (Parser_FuncCallExec( &result, exp, &iterator, QueryOwner) == PARSER_SUCCESS)
					RPNstack.push(result);
				break;


			case MACRO_TOK:
				RPNstack.push(Parser_ReturnMacro((char*)Currenttoken.data.c_str()));
				break;


			case ARRAY_VARIABLE_TOK:
				var = domain->Lookup(Currenttoken.data);
				iterator++;
				for(int u=0;u<VAR_SUBSCRIPT_MAX;u++)
					dims[u] = 0;
				if(Parse_ArraySubscripts( (int*)&dims, exp, &iterator, QueryOwner, domain)!=PARSER_SUCCESS)
				{ 
					//ERROR!
				}


				var = var->ArrayGetRef( (int*)&dims, true);
				Currenttoken.ResolvedVariable = var;
				Currenttoken.type = PARSER_VARIABLE;
				RPNstack.push(Currenttoken);
				break;

			case VARIANT_VARIABLE_TOK:
				var = domain->Lookup(Currenttoken.data);
				Currenttoken.ResolvedVariable = var;
				Currenttoken.type = PARSER_VARIABLE;
				RPNstack.push(Currenttoken);
				break; 

			//Handle all the brackets.
			case LFT_BRACKET_TOK:
				OPstack.push(Currenttoken);
				break;
			case RHT_BRACKET_TOK:
				while( (OPstack.size()>1) && (OPstack.top().type!=LFT_BRACKET_TOK) )
				{
					token temp = OPstack.top();
					OPstack.pop();
					RPNstack.push(temp);
					//TODO: Errorcheck here to see if OPstack empty: no match left bracket.
				};

				//TODO: Errorcheck here to see if last token is '(': should be.
				OPstack.pop(); //Get rid of that left bracket.
				break;

			//Handle all the operators.
			case MATH_OP_TOK: case EQUAL_TOK: case COMP_OP_TOK: case DOUBLE_EQUAL_TOK:

				while(OPstack.size()){
					char opcode = Operator(Currenttoken.data);
					int prec = GetPrecedence(opcode);
					int stackopPrec = GetPrecedence(Operator(OPstack.top().data));
					if((Operator(OPstack.top().data)) && 
						((op_left_assoc(opcode)) && (prec <= stackopPrec)) ||
						(!op_left_assoc(opcode) && (prec < stackopPrec)))
						{
							RPNstack.push(OPstack.top());
							OPstack.pop();
					}else{ break;}
				}
				OPstack.push(Currenttoken);
				break;


			//Other tokens should not be in here, but this will trap them if they are.
			default:
				break;
		}

	}

	//Dump operator stack onto the RPN stack.
	while(OPstack.size()){
		RPNstack.push(OPstack.top());
		OPstack.pop();		
	}

	//Now we need to reverse the stack in order to pop off the tokens in the right order
	//for the vector (RPNExpression) sake.
	while(RPNstack.size()){
		OPstack.push(RPNstack.top()); //We are reversing RPNstack -> OPstack (which was empty)
		RPNstack.pop();		
	}

	//Save everything to our expression output.
	while(OPstack.size()){
		RPNExpression.push_back(OPstack.top());
		OPstack.pop();		
	}

	return RPNExpression;
}
 

token EvaluateRPN(std::vector<token> exp, Interpreter* QueryOwner){

	token returndata;
	std::stack<token> PARAMstack;
	token LastToken;
	int iterator = 0;

	for(; iterator<exp.size();iterator++){
		token Currenttoken = exp[iterator];
		token tTemp1;
		token tTemp2;
		int* nTemp;
		__int64 n64Temp;

		switch(Currenttoken.type){
			//DO ALL THE OPTIMIZER CONVERSIONS FOR THE ORIGINAL TOKENTYPES HERE.
			//To optimize in the future, do all of this in the lexer.
			case NUMHEX_TOK:
				//evaluate to int.
				Currenttoken.type = OPT_INT32_TOK;
				HexToDec( Currenttoken.data.c_str(), Currenttoken.nValue);
				Currenttoken.data = "";
				PARAMstack.push(Currenttoken);
				break;
			case INT32_TOK:
				Currenttoken.nValue = atoi( Currenttoken.data.c_str());
				Currenttoken.type = OPT_INT32_TOK;
				Currenttoken.data = "";
				PARAMstack.push(Currenttoken);
				break;
			case INT64_TOK:
				Currenttoken.n64Value = _atoi64( Currenttoken.data.c_str());
				Currenttoken.type = OPT_INT64_TOK;
				Currenttoken.data = "";
				PARAMstack.push(Currenttoken);
				break;
			case DOUBLE_TOK:
				Currenttoken.fValue = atof( Currenttoken.data.c_str());
				Currenttoken.type = OPT_DOUBLE_TOK;
				Currenttoken.data = "";
				PARAMstack.push(Currenttoken);
				break;
			case STRINGLITERAL_TOK:
				{
				char* addr = (char*)Currenttoken.data.c_str();
				int l = strlen(addr)+1;
				Currenttoken.szValue = new char[l];
				strcpy(Currenttoken.szValue, addr);
				Currenttoken.type = OPT_STRINGLITERAL_TOK;
				PARAMstack.push(Currenttoken);
				}
				break;

			case PARSER_VARIABLE:
				//PARAMstack.push(GetTokenRepresentation(Currenttoken.ResolvedVariable));
				//Leave Variables intact - we can get the type we need when we do the operation.
				PARAMstack.push(Currenttoken);
				break;

			case OPT_INT32_TOK: case OPT_INT64_TOK: case OPT_DOUBLE_TOK: case OPT_STRINGLITERAL_TOK:
				PARAMstack.push(Currenttoken);
				break;

			case COMP_OP_TOK: 
				tTemp1 = PARAMstack.top();PARAMstack.pop();
				if(PARAMstack.size()>0){
					tTemp2 = PARAMstack.top();PARAMstack.pop();
					if(Currenttoken.data == ">")
						PARAMstack.push(GreaterLessThan( tTemp2, tTemp1));
					else if(Currenttoken.data == "<")
						PARAMstack.push(GreaterLessThan( tTemp1, tTemp2));
					else if(Currenttoken.data == "<=")
						PARAMstack.push(GreaterLessThanEqual( tTemp1, tTemp2));
					else if(Currenttoken.data == ">=")
						PARAMstack.push(GreaterLessThanEqual( tTemp2, tTemp1));
					else if(Currenttoken.data == "<>")
						PARAMstack.push(Difference(tTemp1,tTemp2));

					Free_Token_Attributes( &tTemp1);
					Free_Token_Attributes( &tTemp2);
				}else{
					Free_Token_Attributes( &tTemp1);
					//ERROR!
				}
				break;

			case EQUAL_TOK: case DOUBLE_EQUAL_TOK:
				tTemp1 = PARAMstack.top();PARAMstack.pop();
				if(PARAMstack.size()>0){
					tTemp2 = PARAMstack.top();PARAMstack.pop();
					if(Currenttoken.data == "=")
						PARAMstack.push(Equality( tTemp1, tTemp2));
					else
						PARAMstack.push(CASEEquality( tTemp1, tTemp2));

					Free_Token_Attributes( &tTemp1);
					Free_Token_Attributes( &tTemp2);
				}else{
					Free_Token_Attributes( &tTemp1);
					//ERROR!
				}
				break;


			//OPERATORS...We actually need to do the operations here.
			case MATH_OP_TOK:

				tTemp1 = PARAMstack.top();PARAMstack.pop();
				if(PARAMstack.size()>0){
					tTemp2 = PARAMstack.top();PARAMstack.pop();
					if(Currenttoken.data == "+")
						PARAMstack.push(Addition( tTemp2, tTemp1));
					if(Currenttoken.data == "-")
						PARAMstack.push(Subtraction( tTemp2, tTemp1));
					if(Currenttoken.data == "&")
						PARAMstack.push(Concat( tTemp2, tTemp1));
					if(Currenttoken.data == "*")
						PARAMstack.push(Multiplication( tTemp2, tTemp1));
					if(Currenttoken.data == "/")
						PARAMstack.push(Division( tTemp2, tTemp1));

					Free_Token_Attributes( &tTemp1);
					Free_Token_Attributes( &tTemp2);
					break;
				}else{	//This is an operation requiring a single operand.
						tTemp2.type = OPT_INT32_TOK;
						tTemp2.nValue = 0;
						if(Currenttoken.data == "-")
							PARAMstack.push(Subtraction( tTemp2, tTemp1));

						Free_Token_Attributes( &tTemp1);

				}
				break;
			}
	}

	//std::cout << "Size: " << PARAMstack.size() << '\n';
	//Sleep(8000);

	returndata = PARAMstack.top();
	return returndata;
}




void Shunt_Test(void){
	Interpreter inte( "test", 0);
	std::cout << "SHUNTER TEST:\n\nTokens:  ";
	std::vector<token> test;
	//test.push_back( CreateToken(INT32_TOK, "9"));
	test.push_back( CreateToken(MATH_OP_TOK, "-"));
	test.push_back( CreateToken(INT32_TOK, "64"));
	test.push_back( CreateToken(MATH_OP_TOK, "+"));
	test.push_back( CreateToken(INT32_TOK, "9"));
	std::vector<token> results = ShuntExpression(&test, &inte);
	while(results.size()){
		std::cout << results[results.size()-1].data << ' ';
		results.pop_back();
	}
	std::cout << '\n';
}

int HexToDec(const char *szHex, int &nDec)
{
	szHex+=2; //Not allowed 0x part of 0xffff
	// Really crappy hex conversion
	int i = (int)strlen(szHex) - 1;

	nDec = 0;
	int nMult = 1;
	for (int j = 0; j < 8; ++j)
	{
		if (i < 0)
			break;

		if (szHex[i] >= '0' && szHex[i] <= '9')
			nDec += (szHex[i] - '0') * nMult;
		else if (szHex[i] >= 'A' && szHex[i] <= 'F')
			nDec += (((szHex[i] - 'A'))+10) * nMult;
		else if (szHex[i] >= 'a' && szHex[i] <= 'f')
			nDec += (((szHex[i] - 'a'))+10) * nMult;
		else
		{
			nDec = 0;					// Set value as 0
			return false;
		}

		--i;
		nMult = nMult * 16;
	}

	if (i != -1)
	{
		nDec = 0;
		return false;
	}
	else
		return true;
	
}

token GetTokenRepresentation(Variant* var){
	token ret;
	char* sTemp;
	//Set defaults.
	ret.type = OPT_INT32_TOK;
	ret.nValue = 0;

	switch(var->VarType){
		case VAR_INT32:
			ret.type = OPT_INT32_TOK;
			ret.data = "";
			ret.nValue = var->GetInt32();
			return ret;
			break;

		case VAR_INT64:
			ret.type = OPT_INT64_TOK;
			ret.data = "";
			ret.n64Value = var->GetInt64();
			return ret;
			break;

		case VAR_DOUBLE:
			ret.type = OPT_DOUBLE_TOK;
			ret.data = "";
			ret.fValue = var->GetDouble();
			return ret;
			break;

		case VAR_STRING:
			ret.type = OPT_STRINGLITERAL_TOK;
			ret.data = "";
			ret.szValue = new char[strlen(var->GetString())+1];
			strcpy(ret.szValue, var->GetString());
			return ret;
			break;

		case VAR_ARRAY:
			ret.type = OPT_INT32_TOK;
			ret.data = "";
			ret.nValue = 0;
			return ret;
			break;

		case VAR_REFERENCE:
			ret.type = OPT_INT32_TOK;
			ret.data = "";
			ret.nValue = var->GetInt32();
			return ret;
			break;

		case VAR_HWND:
			ret.type = OPT_INT32_TOK;
			ret.data = "";
			ret.nValue = var->GetInt32();
			return ret;
			break;
	}

	return ret;
}




















//##################################################################
//PARSER OPERATIONS
//Code that performs the various operations to these operands.
//##################################################################


token Equality(token tTemp1,token tTemp2){
	token result;
	double fTemp;
	result.type = OPT_INT32_TOK;
	result.nValue = 0; //Default: not equal.
		
	//###############CONVERT Str +  to reduce code bloat.
	//if(tTemp1.type == OPT_STRINGLITERAL_TOK){
	//	tTemp1.type = OPT_INT32_TOK;
	//	tTemp1.nValue = atoi(tTemp1.szValue);
	//}else if (tTemp1.type == PARSER_VARIABLE){
	//	Variant* vTemp = tTemp1.ResolvedVariable;
	//	tTemp1.type = OPT_DOUBLE_TOK;
	//	tTemp1.fValue = vTemp->GetDouble();
	//}

	switch(tTemp2.type){
		case OPT_INT32_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = (tTemp1.nValue == tTemp2.nValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value == (__int64)tTemp2.nValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == (double)tTemp2.nValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) == (double)tTemp2.nValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() == (double)tTemp2.nValue);
					break;
			}
			break;
		case OPT_INT64_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((__int64)tTemp1.nValue == tTemp2.n64Value);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value == tTemp2.n64Value);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == (double)tTemp2.n64Value);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) == (double)tTemp2.n64Value);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() == (double)tTemp2.n64Value);
					break;
			}
			break;
		case OPT_DOUBLE_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue == tTemp2.fValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value == tTemp2.fValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == tTemp2.fValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) == tTemp2.fValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() == tTemp2.fValue);
					break;
			}

		break;

		case OPT_STRINGLITERAL_TOK:
			fTemp = atof(tTemp2.szValue);
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue == fTemp);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value == fTemp);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == fTemp);
					break;
				case OPT_STRINGLITERAL_TOK:
					if(!stricmp(tTemp1.szValue,tTemp2.szValue))
						result.nValue = 1;
					else
						result.nValue = 0;
					break;
				case PARSER_VARIABLE:
					if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
					{
						if(!stricmp(tTemp1.ResolvedVariable->GetString(),tTemp2.szValue))
							result.nValue = 1;
						else
							result.nValue = 0;
					}else{
						Variant* vTemp = tTemp1.ResolvedVariable;
						result.nValue = (vTemp->GetDouble() == fTemp);
					}
					break;
			}
			break;

		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_STRING){
				Token_ForceStrType( &tTemp1);									//POSSIBLE MEMORY LEAK HERE!!!!!!!!!!!
				
				if(!stricmp(tTemp1.szValue,tTemp2.ResolvedVariable->GetString()))
					result.nValue = 1;
				else
					result.nValue = 0;

			}else{
				fTemp = tTemp2.ResolvedVariable->GetDouble();
				switch(tTemp1.type){
					case OPT_INT32_TOK:
						result.nValue = ((double)tTemp1.nValue == fTemp);
						break;
					case OPT_INT64_TOK:
						result.nValue = ((double)tTemp1.n64Value == fTemp);
						break;
					case OPT_DOUBLE_TOK:
						result.nValue = (tTemp1.fValue == fTemp);
						break;
					case OPT_STRINGLITERAL_TOK:
						result.nValue = (atof(tTemp1.szValue) == fTemp);
						break;
					case PARSER_VARIABLE:
						if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
						{
							if(!stricmp(tTemp1.ResolvedVariable->GetString(),tTemp2.ResolvedVariable->GetString()))
								result.nValue = 1;
							else
								result.nValue = 0;
						}else{
							Variant* vTemp = tTemp1.ResolvedVariable;
							result.nValue = (vTemp->GetDouble() == fTemp);
						}
						break;
				}
			}
			break;


	}
	return result;
}




token Difference(token tTemp1,token tTemp2){
	token result = Equality( tTemp1, tTemp2);
	//Invert the equality result to get the anti-equality
	if(result.nValue)
		result.nValue = 0;
	else
		result.nValue = 1;
	return result;
}



token CASEEquality(token tTemp1,token tTemp2){
	token result;
	double fTemp;
	result.type = OPT_INT32_TOK;
	result.nValue = 0; //Default: not equal.

	switch(tTemp2.type){
		case OPT_INT32_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = (tTemp1.nValue == tTemp2.nValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value == (__int64)tTemp2.nValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == (double)tTemp2.nValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) == (double)tTemp2.nValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() == (double)tTemp2.nValue);
					break;
			}
			break;
		case OPT_INT64_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((__int64)tTemp1.nValue == tTemp2.n64Value);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value == tTemp2.n64Value);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == (double)tTemp2.n64Value);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) == (double)tTemp2.n64Value);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() == (double)tTemp2.n64Value);
					break;
			}
			break;
		case OPT_DOUBLE_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue == tTemp2.fValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value == tTemp2.fValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == tTemp2.fValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) == tTemp2.fValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() == tTemp2.fValue);
					break;
			}

		break;

		case OPT_STRINGLITERAL_TOK:
			fTemp = atof(tTemp2.szValue);
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue == fTemp);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value == fTemp);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue == fTemp);
					break;
				case OPT_STRINGLITERAL_TOK:
					if(!strcmp(tTemp1.szValue,tTemp2.szValue))
						result.nValue = 1;
					else
						result.nValue = 0;
					break;
				case PARSER_VARIABLE:
					if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
					{
						if(!strcmp(tTemp1.ResolvedVariable->GetString(),tTemp2.szValue))
							result.nValue = 1;
						else
							result.nValue = 0;
					}else{
						Variant* vTemp = tTemp1.ResolvedVariable;
						result.nValue = (vTemp->GetDouble() == fTemp);
					}
					break;
			}
			break;

		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_STRING){
				Token_ForceStrType( &tTemp1);									//POSSIBLE MEMORY LEAK HERE!!!!!!!!!!!
				
				if(!strcmp(tTemp1.szValue,tTemp2.ResolvedVariable->GetString()))
					result.nValue = 1;
				else
					result.nValue = 0;

			}else{
				fTemp = tTemp2.ResolvedVariable->GetDouble();
				switch(tTemp1.type){
					case OPT_INT32_TOK:
						result.nValue = ((double)tTemp1.nValue == fTemp);
						break;
					case OPT_INT64_TOK:
						result.nValue = ((double)tTemp1.n64Value == fTemp);
						break;
					case OPT_DOUBLE_TOK:
						result.nValue = (tTemp1.fValue == fTemp);
						break;
					case OPT_STRINGLITERAL_TOK:
						result.nValue = (atof(tTemp1.szValue) == fTemp);
						break;
					case PARSER_VARIABLE:
						if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
						{
							if(!strcmp(tTemp1.ResolvedVariable->GetString(),tTemp2.ResolvedVariable->GetString()))
								result.nValue = 1;
							else
								result.nValue = 0;
						}else{
							Variant* vTemp = tTemp1.ResolvedVariable;
							result.nValue = (vTemp->GetDouble() == fTemp);
						}
						break;
				}
			}
			break;


	}
	return result;
}



token GreaterLessThan(token tTemp1,token tTemp2){
	token result;
	double fTemp;
	result.type = OPT_INT32_TOK;
	result.nValue = 0; //Default: not equal.
		
	switch(tTemp2.type){
		case OPT_INT32_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = (tTemp1.nValue > tTemp2.nValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value > (__int64)tTemp2.nValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue > (double)tTemp2.nValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) > (double)tTemp2.nValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() > (double)tTemp2.nValue);
					break;
			}
			break;
		case OPT_INT64_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((__int64)tTemp1.nValue > tTemp2.n64Value);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value > tTemp2.n64Value);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue > (double)tTemp2.n64Value);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) > (double)tTemp2.n64Value);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() > (double)tTemp2.n64Value);
					break;
			}
			break;
		case OPT_DOUBLE_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue > tTemp2.fValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value > tTemp2.fValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue > tTemp2.fValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) > tTemp2.fValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() > tTemp2.fValue);
					break;
			}
			break;

		case OPT_STRINGLITERAL_TOK:
			fTemp = atof(tTemp2.szValue);
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue > fTemp);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value > fTemp);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue > fTemp);
					break;
				case OPT_STRINGLITERAL_TOK:
					if(stricmp(tTemp1.szValue,tTemp2.szValue) > 0)
						result.nValue = 1;
					else
						result.nValue = 0;
					break;
				case PARSER_VARIABLE:
					if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
					{
						if(stricmp(tTemp1.ResolvedVariable->GetString(),tTemp2.szValue) > 0)
							result.nValue = 1;
						else
							result.nValue = 0;
					}else{
						Variant* vTemp = tTemp1.ResolvedVariable;
						result.nValue = (vTemp->GetDouble() > fTemp);
					}
					break;
			}
			break;

		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_STRING){
				Token_ForceStrType( &tTemp1);									//POSSIBLE MEMORY LEAK HERE!!!!!!!!!!!
				
				if(stricmp(tTemp1.szValue,tTemp2.ResolvedVariable->GetString()) > 0)
					result.nValue = 1;
				else
					result.nValue = 0;

			}else{
				fTemp = tTemp2.ResolvedVariable->GetDouble();
				switch(tTemp1.type){
					case OPT_INT32_TOK:
						result.nValue = ((double)tTemp1.nValue > fTemp);
						break;
					case OPT_INT64_TOK:
						result.nValue = ((double)tTemp1.n64Value > fTemp);
						break;
					case OPT_DOUBLE_TOK:
						result.nValue = (tTemp1.fValue > fTemp);
						break;
					case OPT_STRINGLITERAL_TOK:
						result.nValue = (atof(tTemp1.szValue) > fTemp);
						break;
					case PARSER_VARIABLE:
						if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
						{
							if(stricmp(tTemp1.ResolvedVariable->GetString(),tTemp2.ResolvedVariable->GetString()) > 0)
								result.nValue = 1;
							else
								result.nValue = 0;
						}else{
							Variant* vTemp = tTemp1.ResolvedVariable;
							result.nValue = (vTemp->GetDouble() > fTemp);
						}
						break;
				}
			}
			break;


	}
	return result;
}


token GreaterLessThanEqual(token tTemp1,token tTemp2){
	token result;
	double fTemp;
	result.type = OPT_INT32_TOK;
	result.nValue = 0; //Default: not equal.
		
	switch(tTemp2.type){
		case OPT_INT32_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = (tTemp1.nValue >= tTemp2.nValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value >= (__int64)tTemp2.nValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue >= (double)tTemp2.nValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) >= (double)tTemp2.nValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() >= (double)tTemp2.nValue);
					break;
			}
			break;
		case OPT_INT64_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((__int64)tTemp1.nValue >= tTemp2.n64Value);
					break;
				case OPT_INT64_TOK:
					result.nValue = (tTemp1.n64Value >= tTemp2.n64Value);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue >= (double)tTemp2.n64Value);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) >= (double)tTemp2.n64Value);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() >= (double)tTemp2.n64Value);
					break;
			}
			break;
		case OPT_DOUBLE_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue >= tTemp2.fValue);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value >= tTemp2.fValue);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue >= tTemp2.fValue);
					break;
				case OPT_STRINGLITERAL_TOK:
					result.nValue = (atof(tTemp1.szValue) >= tTemp2.fValue);
					break;
				case PARSER_VARIABLE:
					Variant* vTemp = tTemp1.ResolvedVariable;
					result.nValue = (vTemp->GetDouble() >= tTemp2.fValue);
					break;
			}
			break;

		case OPT_STRINGLITERAL_TOK:
			fTemp = atof(tTemp2.szValue);
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					result.nValue = ((double)tTemp1.nValue >= fTemp);
					break;
				case OPT_INT64_TOK:
					result.nValue = ((double)tTemp1.n64Value >= fTemp);
					break;
				case OPT_DOUBLE_TOK:
					result.nValue = (tTemp1.fValue >= fTemp);
					break;
				case OPT_STRINGLITERAL_TOK:
					if(stricmp(tTemp1.szValue,tTemp2.szValue) >= 0)
						result.nValue = 1;
					else
						result.nValue = 0;
					break;
				case PARSER_VARIABLE:
					if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
					{
						if(stricmp(tTemp1.ResolvedVariable->GetString(),tTemp2.szValue) >= 0)
							result.nValue = 1;
						else
							result.nValue = 0;
					}else{
						Variant* vTemp = tTemp1.ResolvedVariable;
						result.nValue = (vTemp->GetDouble() >= fTemp);
					}
					break;
			}
			break;

		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_STRING){
				Token_ForceStrType( &tTemp1);									//POSSIBLE MEMORY LEAK HERE!!!!!!!!!!!
				
				if(stricmp(tTemp1.szValue,tTemp2.ResolvedVariable->GetString()) >= 0)
					result.nValue = 1;
				else
					result.nValue = 0;

			}else{
				fTemp = tTemp2.ResolvedVariable->GetDouble();
				switch(tTemp1.type){
					case OPT_INT32_TOK:
						result.nValue = ((double)tTemp1.nValue >= fTemp);
						break;
					case OPT_INT64_TOK:
						result.nValue = ((double)tTemp1.n64Value >= fTemp);
						break;
					case OPT_DOUBLE_TOK:
						result.nValue = (tTemp1.fValue >= fTemp);
						break;
					case OPT_STRINGLITERAL_TOK:
						result.nValue = (atof(tTemp1.szValue) >= fTemp);
						break;
					case PARSER_VARIABLE:
						if(tTemp1.ResolvedVariable->VarType == VAR_STRING)
						{
							if(stricmp(tTemp1.ResolvedVariable->GetString(),tTemp2.ResolvedVariable->GetString()) >= 0)
								result.nValue = 1;
							else
								result.nValue = 0;
						}else{
							Variant* vTemp = tTemp1.ResolvedVariable;
							result.nValue = (vTemp->GetDouble() >= fTemp);
						}
						break;
				}
			}
			break;


	}
	return result;
}


token Concat(token tTemp2, token tTemp1){
	token result;
	result.type = OPT_STRINGLITERAL_TOK;
	char* temp;
	char* temp2;
	std::ostringstream sTemp1;
	sTemp1.precision(15);
	std::ostringstream sTemp2;
	sTemp2.precision(15);
	int length = 0;



	switch(tTemp2.type){
		case OPT_INT32_TOK:
			sTemp1 << tTemp2.nValue;
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					sTemp2 << tTemp1.nValue;
					break;
				case OPT_INT64_TOK:
					sTemp2 << tTemp1.n64Value;
					break;
				case OPT_DOUBLE_TOK:
					sTemp2 << tTemp1.fValue;
					break;
				case OPT_STRINGLITERAL_TOK:
					length = strlen(tTemp1.szValue) + strlen(sTemp1.str().c_str()) + 1;
					temp = new char[length];
					memcpy(temp, sTemp1.str().c_str(), strlen(sTemp1.str().c_str())+1);
					strcat(temp, tTemp1.szValue);
					result.szValue = temp;
					return result;
					break;
				case PARSER_VARIABLE:
					temp = new char[strlen(sTemp1.str().c_str())+strlen(tTemp1.ResolvedVariable->GetString())+1];
					strcpy(temp, sTemp1.str().c_str());
					strcat(temp, tTemp1.ResolvedVariable->GetString());
					result.szValue = temp;
					return result;
					break;
			}
			length = strlen(sTemp1.str().c_str()) + strlen(sTemp2.str().c_str()) + 1;
			temp = new char[length];
			memcpy(temp, sTemp1.str().c_str(), strlen(sTemp1.str().c_str())+1);
			strcat(temp, sTemp2.str().c_str());
			break;
		case OPT_INT64_TOK:
			sTemp1 << tTemp2.n64Value;
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					sTemp2 << tTemp1.nValue;
					break;
				case OPT_INT64_TOK:
					sTemp2 << tTemp1.n64Value;
					break;
				case OPT_DOUBLE_TOK:
					sTemp2 << tTemp1.fValue;
					break;
				case OPT_STRINGLITERAL_TOK:
					length = strlen(tTemp1.szValue) + strlen(sTemp1.str().c_str()) + 1;
					temp = new char[length];
					memcpy(temp, sTemp1.str().c_str(), strlen(sTemp1.str().c_str())+1);
					strcat(temp, tTemp1.szValue);
					result.szValue = temp;
					return result;
					break;
				case PARSER_VARIABLE:
					temp = new char[strlen(sTemp1.str().c_str())+strlen(tTemp1.ResolvedVariable->GetString())+1];
					strcpy(temp, sTemp1.str().c_str());
					strcat(temp, tTemp1.ResolvedVariable->GetString());
					result.szValue = temp;
					return result;
					break;
			}
			length = strlen(sTemp1.str().c_str()) + strlen(sTemp2.str().c_str()) + 1;
			temp = new char[length];
			memcpy(temp, sTemp1.str().c_str(), strlen(sTemp1.str().c_str())+1);
			strcat(temp, sTemp2.str().c_str());
			break;
		case OPT_DOUBLE_TOK:
			sTemp1 << tTemp2.fValue;
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					sTemp2 << tTemp1.nValue;
					break;
				case OPT_INT64_TOK:
					sTemp2 << tTemp1.n64Value;
					break;
				case OPT_DOUBLE_TOK:
					sTemp2 << tTemp1.fValue;
					break;
				case OPT_STRINGLITERAL_TOK:
					length = strlen(tTemp1.szValue) + strlen(sTemp1.str().c_str()) + 1;
					temp = new char[length];
					memcpy(temp, tTemp1.szValue, strlen(tTemp1.szValue)+1);
					strcat(temp, sTemp1.str().c_str());
					result.szValue = temp;
					return result;
					break;
				case PARSER_VARIABLE:
					temp = new char[strlen(sTemp1.str().c_str())+strlen(tTemp1.ResolvedVariable->GetString())+1];
					strcpy(temp, sTemp1.str().c_str());
					strcat(temp, tTemp1.ResolvedVariable->GetString());
					result.szValue = temp;
					return result;
					break;
			}
			length = strlen(sTemp1.str().c_str()) + strlen(sTemp2.str().c_str()) + 1;
			temp = new char[length];
			memcpy(temp, sTemp1.str().c_str(), strlen(sTemp1.str().c_str())+1);
			strcat(temp, sTemp2.str().c_str());
			break;

		case OPT_STRINGLITERAL_TOK:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					sTemp2 << tTemp1.nValue;
					break;
				case OPT_INT64_TOK:
					sTemp2 << tTemp1.n64Value;
					break;
				case OPT_DOUBLE_TOK:
					sTemp2 << tTemp1.fValue;
					break;
				case OPT_STRINGLITERAL_TOK:
					length = strlen(tTemp1.szValue) + strlen(tTemp2.szValue) + 1;
					temp = new char[length];
					strcpy(temp, tTemp2.szValue);
					strcat(temp, tTemp1.szValue);
					result.szValue = temp;
					return result;
					break;
				case PARSER_VARIABLE:
					temp = new char[strlen(tTemp2.szValue)+strlen(tTemp1.ResolvedVariable->GetString())+1];
					strcpy(temp, tTemp2.szValue);
					strcat(temp, tTemp1.ResolvedVariable->GetString());
					result.szValue = temp;
					return result;
					break;
			}
			length = strlen(tTemp2.szValue) + strlen(sTemp2.str().c_str()) + 1;
			temp = new char[length];
			strcpy(temp, tTemp2.szValue);
			strcat(temp, sTemp2.str().c_str());
			break;


		case PARSER_VARIABLE:
			switch(tTemp1.type){
				case OPT_INT32_TOK:
					sTemp2 << tTemp1.nValue;
					break;
				case OPT_INT64_TOK:
					sTemp2 << tTemp1.n64Value;
					break;
				case OPT_DOUBLE_TOK:
					sTemp2 << tTemp1.fValue;
					break;
				case OPT_STRINGLITERAL_TOK:
					length = strlen(tTemp1.szValue) + strlen(tTemp2.ResolvedVariable->GetString()) + 1;
					temp = new char[length];
					strcpy(temp, tTemp2.ResolvedVariable->GetString());
					strcat(temp, tTemp1.szValue);
					result.szValue = temp;
					return result;
					break;
				case PARSER_VARIABLE:
					temp = new char[strlen(tTemp2.ResolvedVariable->GetString())+strlen(tTemp1.ResolvedVariable->GetString())+1];
					strcpy(temp, tTemp2.ResolvedVariable->GetString());
					strcat(temp, tTemp1.ResolvedVariable->GetString());
					result.szValue = temp;
					return result;
					break;
			}
			length = strlen(tTemp2.ResolvedVariable->GetString()) + strlen(sTemp2.str().c_str()) + 1;
			temp = new char[length];
			strcpy(temp, tTemp2.ResolvedVariable->GetString());
			strcat(temp, sTemp2.str().c_str());
			break;


	}
	result.szValue = temp;
	return result;
}


token Addition(token tTemp2,token tTemp1){
	token result;
	int nTemp;
	__int64 n64Temp;
	double fTemp;
	token tok;

	switch(tTemp2.type){
		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_INT32)
			{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_INT64)
			{
				tok.type = OPT_INT64_TOK;
				tok.n64Value = tTemp2.ResolvedVariable->GetInt64();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_DOUBLE)
			{
				tok.type = OPT_DOUBLE_TOK;
				tok.fValue = tTemp2.ResolvedVariable->GetDouble();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_STRING)
			{
				tok.type = OPT_STRINGLITERAL_TOK;
				tok.szValue = tTemp2.ResolvedVariable->GetString();
			}else{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			return Addition(tok, tTemp1);
			break;

		case OPT_INT32_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				nTemp = tTemp1.nValue + tTemp2.nValue;
				n64Temp = (__int64)(tTemp1.nValue) + (__int64)(tTemp2.nValue);
				if ( (__int64)(nTemp) != n64Temp )
				{	// Promote to int64 because of int32 overflow
					result.type = OPT_INT64_TOK;
					result.n64Value = n64Temp;
				}else{
					result.type = OPT_INT32_TOK;
					result.nValue = nTemp;
				}
			}

			else if (tTemp1.type == OPT_INT64_TOK)
			{// As 2nd operation is a 64bit, promote anyway
				result.n64Value = (tTemp1.n64Value) + (__int64)(tTemp2.nValue);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.nValue + tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				nTemp = atoi(tTemp1.szValue);
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Addition(tTemp2, result);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Addition(tTemp2, result);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Addition(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				//Because additions are the same from both directions, we can do this.
				return Addition(tTemp1, tTemp2);
			}
			break;



		case OPT_INT64_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.n64Value = (__int64)(tTemp1.nValue) + (__int64)(tTemp2.n64Value);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.n64Value = (tTemp1.n64Value) + (__int64)(tTemp2.n64Value);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.n64Value + tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Addition(tTemp2, result);
				}
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				return Addition(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				//Because additions are the same from both directsions, we can do this.
				return Addition(tTemp1, tTemp2);
			}
			break;			
			
			
		

		case OPT_DOUBLE_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.fValue = (double)(tTemp1.nValue) + tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.fValue = (double)(tTemp1.n64Value) + (tTemp2.fValue);
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp2.fValue + tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				fTemp = atof(tTemp1.szValue);
				result.fValue = fTemp;
				result.type = OPT_DOUBLE_TOK;
				return Addition(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				//Because additions are the same from both directsions, we can do this.
				return Addition(tTemp1, tTemp2);
			}
			break;			

		case OPT_STRINGLITERAL_TOK:
				nTemp = atoi(tTemp2.szValue);
				n64Temp = _atoi64(tTemp2.szValue);
				fTemp = atof(tTemp2.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Addition(result, tTemp1);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Addition(result, tTemp1);
				}else if (tTemp1.type == PARSER_VARIABLE){
					//Because additions are the same from both directsions, we can do this.
					return Addition(tTemp1, tTemp2);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Addition(result, tTemp1);
				break;

		default:
				result.nValue = 0;
				result.type = OPT_INT32_TOK;
	}

	return result;
}

token Subtraction(token tTemp1, token tTemp2){
	token result;
	int nTemp;
	__int64 n64Temp;
	double fTemp;
	token tok;


	if(tTemp1.type == PARSER_VARIABLE){
		Variant* var = tTemp1.ResolvedVariable;
		switch(var->VarType){
			case VAR_INT32:
				tTemp1.type = OPT_INT32_TOK;
				tTemp1.nValue = var->GetInt32();
				break;
			case VAR_INT64:
				tTemp1.type = OPT_INT64_TOK;
				tTemp1.n64Value = var->GetInt64();
				break;
			case VAR_DOUBLE:
				tTemp1.type = OPT_DOUBLE_TOK;
				tTemp1.fValue = var->GetDouble();
				break;
			case VAR_STRING:
				tTemp1.type = OPT_STRINGLITERAL_TOK;
				tTemp1.szValue = var->GetString();
				break;
			default:
				tTemp1.type = OPT_INT32_TOK;
				tTemp1.nValue = var->GetInt32();
		}
	}


	switch(tTemp2.type){
		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_INT32)
			{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_INT64)
			{
				tok.type = OPT_INT64_TOK;
				tok.n64Value = tTemp2.ResolvedVariable->GetInt64();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_DOUBLE)
			{
				tok.type = OPT_DOUBLE_TOK;
				tok.fValue = tTemp2.ResolvedVariable->GetDouble();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_STRING)
			{
				tok.type = OPT_STRINGLITERAL_TOK;
				tok.szValue = tTemp2.ResolvedVariable->GetString();
			}
			else{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			return SubtractionReverse(tok, tTemp1);
			break;

		case OPT_INT32_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				nTemp = tTemp1.nValue - tTemp2.nValue;
				n64Temp = (__int64)(tTemp1.nValue) - (__int64)(tTemp2.nValue);
				if ( (__int64)(nTemp) != n64Temp )
				{	// Promote to int64 because of int32 overflow
					result.type = OPT_INT64_TOK;
					result.n64Value = n64Temp;
				}else{
					result.type = OPT_INT32_TOK;
					result.nValue = nTemp;
				}
			}

			else if (tTemp1.type == OPT_INT64_TOK)
			{// As 2nd operation is a 64bit, promote anyway
				result.n64Value = (tTemp1.n64Value) - (__int64)(tTemp2.nValue);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.nValue - tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				nTemp = atoi(tTemp1.szValue);
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Subtraction(tTemp2, result);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Subtraction(tTemp2, result);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Subtraction(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				return SubtractionReverse(tTemp1, tTemp2);
			}
			break;



		case OPT_INT64_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.n64Value = (__int64)(tTemp1.nValue) - (__int64)(tTemp2.n64Value);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.n64Value = (tTemp1.n64Value) - (__int64)(tTemp2.n64Value);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.n64Value - tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return SubtractionReverse(tTemp2, result);
				}
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				return SubtractionReverse(tTemp2, result);
			}
			break;			
			
			
		

		case OPT_DOUBLE_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.fValue = (double)(tTemp1.nValue) - tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.fValue = (double)(tTemp1.n64Value) - (tTemp2.fValue);
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue - tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				fTemp = atof(tTemp1.szValue);
				result.fValue = fTemp;
				result.type = OPT_DOUBLE_TOK;
				return SubtractionReverse(tTemp2, result);
			}
			break;			

		case OPT_STRINGLITERAL_TOK:
				nTemp = atoi(tTemp2.szValue);
				n64Temp = _atoi64(tTemp2.szValue);
				fTemp = atof(tTemp2.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return SubtractionReverse(result, tTemp1);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return SubtractionReverse(result, tTemp1);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return SubtractionReverse(result, tTemp1);
				break;

		default:
				result.nValue = 0;
				result.type = OPT_INT32_TOK;
	}

	return result;
}


//Same as above, but with operands switched.

token SubtractionReverse(token tTemp2, token tTemp1){
	token result;
	int nTemp;
	__int64 n64Temp;
	double fTemp;
	token tok;

	switch(tTemp2.type){
		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_INT32)
			{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_INT64)
			{
				tok.type = OPT_INT64_TOK;
				tok.n64Value = tTemp2.ResolvedVariable->GetInt64();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_DOUBLE)
			{
				tok.type = OPT_DOUBLE_TOK;
				tok.fValue = tTemp2.ResolvedVariable->GetDouble();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_STRING)
			{
				tok.type = OPT_STRINGLITERAL_TOK;
				tok.szValue = tTemp2.ResolvedVariable->GetString();
			}else if (tTemp1.type == PARSER_VARIABLE){

			}
			else{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			return SubtractionReverse(tok, tTemp1);
			break;

		case OPT_INT32_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				nTemp = tTemp1.nValue - tTemp2.nValue;
				n64Temp = (__int64)(tTemp1.nValue) - (__int64)(tTemp2.nValue);
				if ( (__int64)(nTemp) != n64Temp )
				{	// Promote to int64 because of int32 overflow
					result.type = OPT_INT64_TOK;
					result.n64Value = n64Temp;
				}else{
					result.type = OPT_INT32_TOK;
					result.nValue = nTemp;
				}
			}

			else if (tTemp1.type == OPT_INT64_TOK)
			{// As 2nd operation is a 64bit, promote anyway
				result.n64Value = (tTemp1.n64Value) - (__int64)(tTemp2.nValue);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.nValue - tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				nTemp = atoi(tTemp1.szValue);
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Subtraction(tTemp2, result);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Subtraction(tTemp2, result);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Subtraction(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				return SubtractionReverse(tTemp1, tTemp2);
			}
			break;



		case OPT_INT64_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.n64Value = (__int64)(tTemp1.nValue) - (__int64)(tTemp2.n64Value);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.n64Value = (tTemp1.n64Value) - (__int64)(tTemp2.n64Value);
				result.type = OPT_INT64_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.n64Value - tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return SubtractionReverse(tTemp2, result);
				}
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				return SubtractionReverse(tTemp2, result);
			}
			break;			
			
			
		

		case OPT_DOUBLE_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.fValue = (double)(tTemp1.nValue) - tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.fValue = (double)(tTemp1.n64Value) - (tTemp2.fValue);
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue - tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				fTemp = atof(tTemp1.szValue);
				result.fValue = fTemp;
				result.type = OPT_DOUBLE_TOK;
				return SubtractionReverse(tTemp2, result);
			}
			break;			

		case OPT_STRINGLITERAL_TOK:
				nTemp = atoi(tTemp2.szValue);
				n64Temp = _atoi64(tTemp2.szValue);
				fTemp = atof(tTemp2.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return SubtractionReverse(result, tTemp1);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return SubtractionReverse(result, tTemp1);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return SubtractionReverse(result, tTemp1);
				break;

		default:
				result.nValue = 0;
				result.type = OPT_INT32_TOK;
	}

	return result;
}






token Multiplication(token tTemp2,token tTemp1){
	token result;
	int nTemp;
	__int64 n64Temp;
	double fTemp;
	token tok;

	switch(tTemp2.type){
		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_INT32)
			{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_INT64)
			{
				tok.type = OPT_INT64_TOK;
				tok.n64Value = tTemp2.ResolvedVariable->GetInt64();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_DOUBLE)
			{
				tok.type = OPT_DOUBLE_TOK;
				tok.fValue = tTemp2.ResolvedVariable->GetDouble();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_STRING)
			{
				tok.type = OPT_STRINGLITERAL_TOK;
				tok.szValue = tTemp2.ResolvedVariable->GetString();
			}else{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			return Multiplication(tok, tTemp1);
			break;

		case OPT_INT32_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				nTemp = tTemp1.nValue * tTemp2.nValue;
				n64Temp = (__int64)(tTemp1.nValue) * (__int64)(tTemp2.nValue);
				fTemp = (double)(tTemp1.nValue) * (double)(tTemp2.nValue);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}
				else if ( (__int64)(nTemp) != n64Temp )
				{	// Promote to int64 because of int32 overflow
					result.type = OPT_INT64_TOK;
					result.n64Value = n64Temp;
				}else{
					result.type = OPT_INT32_TOK;
					result.nValue = nTemp;
				}
			}

			else if (tTemp1.type == OPT_INT64_TOK)
			{// As 2nd operation is a 64bit, promote anyway
				n64Temp = (tTemp1.n64Value) * (__int64)(tTemp2.nValue);
				fTemp = (double)(tTemp1.n64Value) * (double)(tTemp2.nValue);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else{
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.nValue * tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				nTemp = atoi(tTemp1.szValue);
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Multiplication(tTemp2, result);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Multiplication(tTemp2, result);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Multiplication(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				//Because additions are the same from both directions, we can do this.
				return Multiplication(tTemp1, tTemp2);
			}
			break;



		case OPT_INT64_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				n64Temp = (__int64)(tTemp1.nValue) * (tTemp2.n64Value);
				fTemp = (double)(tTemp1.nValue) * (double)(tTemp2.n64Value);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else{
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				n64Temp = (tTemp1.n64Value) * (tTemp2.n64Value);
				fTemp = (double)(tTemp1.n64Value) * (double)(tTemp2.n64Value);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else{
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = (double)tTemp2.n64Value * tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Multiplication(tTemp2, result);
				}
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				return Multiplication(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				return Multiplication(tTemp1, tTemp2);
			}
			break;			
			
			
		

		case OPT_DOUBLE_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.fValue = (double)(tTemp1.nValue) * tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.fValue = (double)(tTemp1.n64Value) * (tTemp2.fValue);
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp2.fValue * tTemp1.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				fTemp = atof(tTemp1.szValue);
				result.fValue = fTemp;
				result.type = OPT_DOUBLE_TOK;
				return Multiplication(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				//Because additions are the same from both directsions, we can do this.
				return Multiplication(tTemp1, tTemp2);
			}
			break;			

		case OPT_STRINGLITERAL_TOK:
				nTemp = atoi(tTemp2.szValue);
				n64Temp = _atoi64(tTemp2.szValue);
				fTemp = atof(tTemp2.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Multiplication(result, tTemp1);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Multiplication(result, tTemp1);
				}else if (tTemp1.type == PARSER_VARIABLE){
					//Because additions are the same from both directsions, we can do this.
					return Multiplication(tTemp1, tTemp2);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Multiplication(result, tTemp1);
				break;

		default:
				result.nValue = 0;
				result.type = OPT_INT32_TOK;
	}

	return result;
}





token Division(token tTemp1, token tTemp2){
	token result;
	int nTemp;
	__int64 n64Temp;
	double fTemp;
	token tok;

	if(tTemp1.type == PARSER_VARIABLE){
		Variant* var = tTemp1.ResolvedVariable;
		switch(var->VarType){
			case VAR_INT32:
				tTemp1.type = OPT_INT32_TOK;
				tTemp1.nValue = var->GetInt32();
				break;
			case VAR_INT64:
				tTemp1.type = OPT_INT64_TOK;
				tTemp1.n64Value = var->GetInt64();
				break;
			case VAR_DOUBLE:
				tTemp1.type = OPT_DOUBLE_TOK;
				tTemp1.fValue = var->GetDouble();
				break;
			case VAR_STRING:
				tTemp1.type = OPT_STRINGLITERAL_TOK;
				tTemp1.szValue = var->GetString();
				break;
			default:
				tTemp1.type = OPT_INT32_TOK;
				tTemp1.nValue = var->GetInt32();
		}
	}

	switch(tTemp2.type){
		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_INT32)
			{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_INT64)
			{
				tok.type = OPT_INT64_TOK;
				tok.n64Value = tTemp2.ResolvedVariable->GetInt64();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_DOUBLE)
			{
				tok.type = OPT_DOUBLE_TOK;
				tok.fValue = tTemp2.ResolvedVariable->GetDouble();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_STRING)
			{
				tok.type = OPT_STRINGLITERAL_TOK;
				tok.szValue = tTemp2.ResolvedVariable->GetString();
			}
			else{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			return DivisionReverse(tok, tTemp1);
			break;

		case OPT_INT32_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				nTemp = tTemp1.nValue / tTemp2.nValue;
				n64Temp = (__int64)(tTemp1.nValue) / (__int64)(tTemp2.nValue);
				fTemp = (double)(tTemp1.nValue) / (double)(tTemp2.nValue);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}
				else if ( (__int64)(nTemp) != n64Temp )
				{	// Promote to int64 because of int32 overflow
					result.type = OPT_INT64_TOK;
					result.n64Value = n64Temp;
				}else{
					result.type = OPT_INT32_TOK;
					result.nValue = nTemp;
				}
			}

			else if (tTemp1.type == OPT_INT64_TOK)
			{// As 2nd operation is a 64bit, promote anyway
				fTemp = (double)(tTemp1.n64Value) / (double)(tTemp2.nValue);
				n64Temp = (tTemp1.n64Value) / (__int64)(tTemp2.nValue);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else {
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue / (double)tTemp2.nValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				nTemp = atoi(tTemp1.szValue);
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Division(tTemp2, result);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Division(tTemp2, result);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Division(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				return DivisionReverse(tTemp1, tTemp2);
			}
			break;



		case OPT_INT64_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				n64Temp = (__int64)(tTemp1.nValue) / (__int64)(tTemp2.n64Value);
				fTemp = (double)(tTemp1.nValue) / (double)(tTemp2.n64Value);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else{
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				n64Temp = (tTemp1.n64Value) / (__int64)(tTemp2.n64Value);
				fTemp = (double)(tTemp1.n64Value) / (double)(tTemp2.n64Value);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else{
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue / (double)tTemp2.n64Value;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return DivisionReverse(tTemp2, result);
				}
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				return DivisionReverse(tTemp2, result);
			}
			break;			
			
			
		

		case OPT_DOUBLE_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.fValue = (double)(tTemp1.nValue) / tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.fValue = (double)(tTemp1.n64Value) / (tTemp2.fValue);
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue / tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				fTemp = atof(tTemp1.szValue);
				result.fValue = fTemp;
				result.type = OPT_DOUBLE_TOK;
				return DivisionReverse(tTemp2, result);
			}
			break;			

		case OPT_STRINGLITERAL_TOK:
				nTemp = atoi(tTemp2.szValue);
				n64Temp = _atoi64(tTemp2.szValue);
				fTemp = atof(tTemp2.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return DivisionReverse(result, tTemp1);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return DivisionReverse(result, tTemp1);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return DivisionReverse(result, tTemp1);
				break;

		default:
				result.nValue = 0;
				result.type = OPT_INT32_TOK;
	}

	return result;
}



token DivisionReverse(token tTemp2, token tTemp1){
	token result;
	int nTemp;
	__int64 n64Temp;
	double fTemp;
	token tok;


	if(tTemp1.type == PARSER_VARIABLE){
		Variant* var = tTemp1.ResolvedVariable;
		switch(var->VarType){
			case VAR_INT32:
				tTemp1.type = OPT_INT32_TOK;
				tTemp1.nValue = var->GetInt32();
				break;
			case VAR_INT64:
				tTemp1.type = OPT_INT64_TOK;
				tTemp1.n64Value = var->GetInt64();
				break;
			case VAR_DOUBLE:
				tTemp1.type = OPT_DOUBLE_TOK;
				tTemp1.fValue = var->GetDouble();
				break;
			case VAR_STRING:
				tTemp1.type = OPT_STRINGLITERAL_TOK;
				tTemp1.szValue = var->GetString();
				break;
			default:
				tTemp1.type = OPT_INT32_TOK;
				tTemp1.nValue = var->GetInt32();
		}
	}


	switch(tTemp2.type){
		case PARSER_VARIABLE:
			if(tTemp2.ResolvedVariable->VarType == VAR_INT32)
			{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_INT64)
			{
				tok.type = OPT_INT64_TOK;
				tok.n64Value = tTemp2.ResolvedVariable->GetInt64();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_DOUBLE)
			{
				tok.type = OPT_DOUBLE_TOK;
				tok.fValue = tTemp2.ResolvedVariable->GetDouble();
			}
			else if(tTemp2.ResolvedVariable->VarType == VAR_STRING)
			{
				tok.type = OPT_STRINGLITERAL_TOK;
				tok.szValue = tTemp2.ResolvedVariable->GetString();
			}else if (tTemp1.type == PARSER_VARIABLE){

			}
			else{
				tok.type = OPT_INT32_TOK;
				tok.nValue = tTemp2.ResolvedVariable->GetInt32();
			}
			return DivisionReverse(tok, tTemp1);
			break;

		case OPT_INT32_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				nTemp = tTemp1.nValue / tTemp2.nValue;
				n64Temp = (__int64)(tTemp1.nValue) / (__int64)(tTemp2.nValue);
				fTemp = (double)(tTemp1.nValue) / (double)(tTemp2.nValue);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}
				else if ( (__int64)(nTemp) != n64Temp )
				{	// Promote to int64 because of int32 overflow
					result.type = OPT_INT64_TOK;
					result.n64Value = n64Temp;
				}else{
					result.type = OPT_INT32_TOK;
					result.nValue = nTemp;
				}
			}

			else if (tTemp1.type == OPT_INT64_TOK)
			{// As 2nd operation is a 64bit, promote anyway
				fTemp = (double)(tTemp1.n64Value) / (double)(tTemp2.nValue);
				n64Temp = (tTemp1.n64Value) / (__int64)(tTemp2.nValue);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else {
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue / (double)tTemp2.nValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				nTemp = atoi(tTemp1.szValue);
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return Division(tTemp2, result);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return Division(tTemp2, result);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return Division(tTemp2, result);
			}else if (tTemp1.type == PARSER_VARIABLE){
				return DivisionReverse(tTemp1, tTemp2);
			}
			break;



		case OPT_INT64_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				n64Temp = (__int64)(tTemp1.nValue) / (__int64)(tTemp2.n64Value);
				fTemp = (double)(tTemp1.nValue) / (double)(tTemp2.n64Value);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else{
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				n64Temp = (tTemp1.n64Value) / (__int64)(tTemp2.n64Value);
				fTemp = (double)(tTemp1.n64Value) / (double)(tTemp2.n64Value);
				if(fTemp != (double)n64Temp){
					result.type = OPT_DOUBLE_TOK;
					result.fValue = fTemp;
				}else{
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
				}
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue / (double)tTemp2.n64Value;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				n64Temp = _atoi64(tTemp1.szValue);
				fTemp = atof(tTemp1.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return DivisionReverse(tTemp2, result);
				}
				result.n64Value = n64Temp;
				result.type = OPT_INT64_TOK;
				return DivisionReverse(tTemp2, result);
			}
			break;			
			
			
		

		case OPT_DOUBLE_TOK:
			if(tTemp1.type == OPT_INT32_TOK){
				result.fValue = (double)(tTemp1.nValue) / tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_INT64_TOK)
			{
				result.fValue = (double)(tTemp1.n64Value) / (tTemp2.fValue);
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_DOUBLE_TOK)
			{
				result.fValue = tTemp1.fValue / tTemp2.fValue;
				result.type = OPT_DOUBLE_TOK;
			}
			else if (tTemp1.type == OPT_STRINGLITERAL_TOK)
			{						//ALERT! VERY BAD WAY TO CALCULATE FROM STRINGS! PLEASE FIX
				fTemp = atof(tTemp1.szValue);
				result.fValue = fTemp;
				result.type = OPT_DOUBLE_TOK;
				return DivisionReverse(tTemp2, result);
			}
			break;			

		case OPT_STRINGLITERAL_TOK:
				nTemp = atoi(tTemp2.szValue);
				n64Temp = _atoi64(tTemp2.szValue);
				fTemp = atof(tTemp2.szValue);
				if(fTemp!=n64Temp){
					result.fValue = fTemp;
					result.type = OPT_DOUBLE_TOK;
					return DivisionReverse(result, tTemp1);
				}if(nTemp!=n64Temp){
					result.n64Value = n64Temp;
					result.type = OPT_INT64_TOK;
					return DivisionReverse(result, tTemp1);
				}
				result.nValue = nTemp;
				result.type = OPT_INT32_TOK;
				return DivisionReverse(result, tTemp1);
				break;

		default:
				result.nValue = 0;
				result.type = OPT_INT32_TOK;
	}

	return result;
}

int IsTrue(token* tok){
	switch(tok->type){
		case OPT_INT32_TOK:
			if(tok->nValue)return 1;
			break;
		case OPT_INT64_TOK:
			if(tok->n64Value)return 1;
			break;
		case OPT_DOUBLE_TOK:
			if(tok->fValue)return 1;
			break;
		case OPT_STRINGLITERAL_TOK:
			if(tok->szValue[0]!='\0')return 1;
			break;
		case PARSER_VARIABLE:
			return tok->ResolvedVariable->IsTrue();
			break;

	}
	return 0;
}